(function() {
	var rsplit = function(string, regex) {
		var result = regex.exec(string), retArr = new Array(), first_idx, last_idx, first_bit;
		while (result != null) {
			first_idx = result.index;
			last_idx = regex.lastIndex;
			if ((first_idx) != 0) {
				first_bit = string.substring(0, first_idx);
				retArr.push(string.substring(0, first_idx));
				string = string.slice(first_idx)
			}
			retArr.push(result[0]);
			string = string.slice(result[0].length);
			result = regex.exec(string)
		}
		if (!string == "") {
			retArr.push(string)
		}
		return retArr
	}, chop = function(string) {
		return string.substr(0, string.length - 1)
	}, extend = function(d, s) {
		for ( var n in s) {
			if (s.hasOwnProperty(n)) {
				d[n] = s[n]
			}
		}
	};
	EJS = function(options) {
		options = typeof options == "string" ? {
			view : options
		} : options;
		this.set_options(options);
		if (options.precompiled) {
			this.template = {};
			this.template.process = options.precompiled;
			EJS.update(this.name, this);
			return
		}
		if (options.element) {
			if (typeof options.element == "string") {
				var name = options.element;
				options.element = document.getElementById(options.element);
				if (options.element == null) {
					throw name + "does not exist!"
				}
			}
			if (options.element.value) {
				this.text = options.element.value
			} else {
				this.text = options.element.innerHTML
			}
			this.name = options.element.id;
			this.type = "["
		} else {
			if (options.url) {
				options.url = EJS.endExt(options.url, this.extMatch);
				this.name = this.name ? this.name : options.url;
				var url = options.url;
				var template = EJS.get(this.name, this.cache);
				if (template) {
					return template
				}
				if (template == EJS.INVALID_PATH) {
					return null
				}
				try {
					this.text = EJS.request(url
							+ (this.cache ? "" : "?" + Math.random()))
				} catch (e) {
				}
				if (this.text == null) {
					throw ({
						type : "EJS",
						message : "There is no template at " + url
					})
				}
			}
		}
		var template = new EJS.Compiler(this.text, this.type);
		template.compile(options, this.name);
		EJS.update(this.name, this);
		this.template = template
	};
	EJS.prototype = {
		render : function(object, extra_helpers) {
			object = object || {};
			this._extra_helpers = extra_helpers;
			var v = new EJS.Helpers(object, extra_helpers || {});
			return this.template.process.call(object, object, v)
		},
		update : function(element, options) {
			if (typeof element == "string") {
				element = document.getElementById(element)
			}
			if (options == null) {
				_template = this;
				return function(object) {
					EJS.prototype.update.call(_template, element, object)
				}
			}
			if (typeof options == "string") {
				params = {};
				params.url = options;
				_template = this;
				params.onComplete = function(request) {
					var object = eval(request.responseText);
					EJS.prototype.update.call(_template, element, object)
				};
				EJS.ajax_request(params)
			} else {
				element.innerHTML = this.render(options)
			}
		},
		out : function() {
			return this.template.out
		},
		set_options : function(options) {
			this.type = options.type || EJS.type;
			this.cache = options.cache != null ? options.cache : EJS.cache;
			this.text = options.text || null;
			this.name = options.name || null;
			this.ext = options.ext || EJS.ext;
			this.extMatch = new RegExp(this.ext.replace(/\./, "."))
		}
	};
	EJS.endExt = function(path, match) {
		if (!path) {
			return null
		}
		match.lastIndex = 0;
		return path + (match.test(path) ? "" : this.ext)
	};
	EJS.Scanner = function(source, left, right) {
		extend(this, {
			left_delimiter : left + "%",
			right_delimiter : "%" + right,
			double_left : left + "%%",
			double_right : "%%" + right,
			left_equal : left + "%=",
			left_comment : left + "%#"
		});
		this.SplitRegexp = left == "[" ? /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/
				: new RegExp("(" + this.double_left + ")|(%%"
						+ this.double_right + ")|(" + this.left_equal + ")|("
						+ this.left_comment + ")|(" + this.left_delimiter
						+ ")|(" + this.right_delimiter + "\n)|("
						+ this.right_delimiter + ")|(\n)");
		this.source = source;
		this.stag = null;
		this.lines = 0
	};
	EJS.Scanner.to_text = function(input) {
		if (input == null || input === undefined) {
			return ""
		}
		if (input instanceof Date) {
			return input.toDateString()
		}
		if (input.toString) {
			return input.toString()
		}
		return ""
	};
	EJS.Scanner.prototype = {
		scan : function(block) {
			scanline = this.scanline;
			regex = this.SplitRegexp;
			if (!this.source == "") {
				var source_split = rsplit(this.source, /\n/);
				for ( var i = 0; i < source_split.length; i++) {
					var item = source_split[i];
					this.scanline(item, regex, block)
				}
			}
		},
		scanline : function(line, regex, block) {
			this.lines++;
			var line_split = rsplit(line, regex);
			for ( var i = 0; i < line_split.length; i++) {
				var token = line_split[i];
				if (token != null) {
					try {
						block(token, this)
					} catch (e) {
						throw {
							type : "EJS.Scanner",
							line : this.lines
						}
					}
				}
			}
		}
	};
	EJS.Buffer = function(pre_cmd, post_cmd) {
		this.line = new Array();
		this.script = "";
		this.pre_cmd = pre_cmd;
		this.post_cmd = post_cmd;
		for ( var i = 0; i < this.pre_cmd.length; i++) {
			this.push(pre_cmd[i])
		}
	};
	EJS.Buffer.prototype = {
		push : function(cmd) {
			this.line.push(cmd)
		},
		cr : function() {
			this.script = this.script + this.line.join("; ");
			this.line = new Array();
			this.script = this.script + "\n"
		},
		close : function() {
			if (this.line.length > 0) {
				for ( var i = 0; i < this.post_cmd.length; i++) {
					this.push(pre_cmd[i])
				}
				this.script = this.script + this.line.join("; ");
				line = null
			}
		}
	};
	EJS.Compiler = function(source, left) {
		this.pre_cmd = [ "var ___ViewO = [];" ];
		this.post_cmd = new Array();
		this.source = " ";
		if (source != null) {
			if (typeof source == "string") {
				source = source.replace(/\r\n/g, "\n");
				source = source.replace(/\r/g, "\n");
				this.source = source
			} else {
				if (source.innerHTML) {
					this.source = source.innerHTML
				}
			}
			if (typeof this.source != "string") {
				this.source = ""
			}
		}
		left = left || "<";
		var right = ">";
		switch (left) {
		case "[":
			right = "]";
			break;
		case "<":
			break;
		default:
			throw left + " is not a supported deliminator";
			break
		}
		this.scanner = new EJS.Scanner(this.source, left, right);
		this.out = ""
	};
	EJS.Compiler.prototype = {
		compile : function(options, name) {
			options = options || {};
			this.out = "";
			var put_cmd = "___ViewO.push(";
			var insert_cmd = put_cmd;
			var buff = new EJS.Buffer(this.pre_cmd, this.post_cmd);
			var content = "";
			var clean = function(content) {
				content = content.replace(/\\/g, "\\\\");
				content = content.replace(/\n/g, "\\n");
				content = content.replace(/"/g, '\\"');
				return content
			};
			this.scanner.scan(function(token, scanner) {
				if (scanner.stag == null) {
					switch (token) {
					case "\n":
						content = content + "\n";
						buff.push(put_cmd + '"' + clean(content) + '");');
						buff.cr();
						content = "";
						break;
					case scanner.left_delimiter:
					case scanner.left_equal:
					case scanner.left_comment:
						scanner.stag = token;
						if (content.length > 0) {
							buff.push(put_cmd + '"' + clean(content) + '")')
						}
						content = "";
						break;
					case scanner.double_left:
						content = content + scanner.left_delimiter;
						break;
					default:
						content = content + token;
						break
					}
				} else {
					switch (token) {
					case scanner.right_delimiter:
						switch (scanner.stag) {
						case scanner.left_delimiter:
							if (content[content.length - 1] == "\n") {
								content = chop(content);
								buff.push(content);
								buff.cr()
							} else {
								buff.push(content)
							}
							break;
						case scanner.left_equal:
							buff.push(insert_cmd + "(EJS.Scanner.to_text("
									+ content + ")))");
							break
						}
						scanner.stag = null;
						content = "";
						break;
					case scanner.double_right:
						content = content + scanner.right_delimiter;
						break;
					default:
						content = content + token;
						break
					}
				}
			});
			if (content.length > 0) {
				buff.push(put_cmd + '"' + clean(content) + '")')
			}
			buff.close();
			this.out = buff.script + ";";
			var to_be_evaled = "/*"
					+ name
					+ "*/this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {"
					+ this.out
					+ " return ___ViewO.join('');}}}catch(e){e.lineNumber=null;throw e;}};";
			try {
				eval(to_be_evaled)
			} catch (e) {
				if (typeof JSLINT != "undefined") {
					JSLINT(this.out);
					for ( var i = 0; i < JSLINT.errors.length; i++) {
						var error = JSLINT.errors[i];
						if (error.reason != "Unnecessary semicolon.") {
							error.line++;
							var e = new Error();
							e.lineNumber = error.line;
							e.message = error.reason;
							if (options.view) {
								e.fileName = options.view
							}
							throw e
						}
					}
				} else {
					throw e
				}
			}
		}
	};
	EJS.config = function(options) {
		EJS.cache = options.cache != null ? options.cache : EJS.cache;
		EJS.type = options.type != null ? options.type : EJS.type;
		EJS.ext = options.ext != null ? options.ext : EJS.ext;
		var templates_directory = EJS.templates_directory || {};
		EJS.templates_directory = templates_directory;
		EJS.get = function(path, cache) {
			if (cache == false) {
				return null
			}
			if (templates_directory[path]) {
				return templates_directory[path]
			}
			return null
		};
		EJS.update = function(path, template) {
			if (path == null) {
				return
			}
			templates_directory[path] = template
		};
		EJS.INVALID_PATH = -1
	};
	EJS.config({
		cache : true,
		type : "<",
		ext : ".ejs"
	});
	EJS.Helpers = function(data, extras) {
		this._data = data;
		this._extras = extras;
		extend(this, extras)
	};
	EJS.Helpers.prototype = {
		view : function(options, data, helpers) {
			if (!helpers) {
				helpers = this._extras
			}
			if (!data) {
				data = this._data
			}
			return new EJS(options).render(data, helpers)
		},
		to_text : function(input, null_text) {
			if (input == null || input === undefined) {
				return null_text || ""
			}
			if (input instanceof Date) {
				return input.toDateString()
			}
			if (input.toString) {
				return input.toString().replace(/\n/g, "<br />").replace(/''/g,
						"'")
			}
			return ""
		}
	};
	EJS.newRequest = function() {
		var factories = [ function() {
			return new ActiveXObject("Msxml2.XMLHTTP")
		}, function() {
			return new XMLHttpRequest()
		}, function() {
			return new ActiveXObject("Microsoft.XMLHTTP")
		} ];
		for ( var i = 0; i < factories.length; i++) {
			try {
				var request = factories[i]();
				if (request != null) {
					return request
				}
			} catch (e) {
				continue
			}
		}
	};
	EJS.request = function(path) {
		var request = new EJS.newRequest();
		request.open("GET", path, false);
		try {
			request.send(null)
		} catch (e) {
			return null
		}
		if (request.status == 404 || request.status == 2
				|| (request.status == 0 && request.responseText == "")) {
			return null
		}
		return request.responseText
	};
	EJS.ajax_request = function(params) {
		params.method = (params.method ? params.method : "GET");
		var request = new EJS.newRequest();
		request.onreadystatechange = function() {
			if (request.readyState == 4) {
				if (request.status == 200) {
					params.onComplete(request)
				} else {
					params.onComplete(request)
				}
			}
		};
		request.open(params.method, params.url);
		request.send(null)
	}
})();
EJS.Helpers.prototype.date_tag = function(C, O, A) {
	if (!(O instanceof Date)) {
		O = new Date()
	}
	var B = [ "January", "February", "March", "April", "May", "June", "July",
			"August", "September", "October", "November", "December" ];
	var G = [], D = [], P = [];
	var J = O.getFullYear();
	var H = O.getMonth();
	var N = O.getDate();
	for ( var M = J - 15; M < J + 15; M++) {
		G.push({
			value : M,
			text : M
		})
	}
	for ( var E = 0; E < 12; E++) {
		D.push({
			value : (E),
			text : B[E]
		})
	}
	for ( var I = 0; I < 31; I++) {
		P.push({
			value : (I + 1),
			text : (I + 1)
		})
	}
	var L = this.select_tag(C + "[year]", J, G, {
		id : C + "[year]"
	});
	var F = this.select_tag(C + "[month]", H, D, {
		id : C + "[month]"
	});
	var K = this.select_tag(C + "[day]", N, P, {
		id : C + "[day]"
	});
	return L + F + K
};
EJS.Helpers.prototype.form_tag = function(B, A) {
	A = A || {};
	A.action = B;
	if (A.multipart == true) {
		A.method = "post";
		A.enctype = "multipart/form-data"
	}
	return this.start_tag_for("form", A)
};
EJS.Helpers.prototype.form_tag_end = function() {
	return this.tag_end("form")
};
EJS.Helpers.prototype.hidden_field_tag = function(A, C, B) {
	return this.input_field_tag(A, C, "hidden", B)
};
EJS.Helpers.prototype.input_field_tag = function(A, D, C, B) {
	B = B || {};
	B.id = B.id || A;
	B.value = D || "";
	B.type = C || "text";
	B.name = A;
	return this.single_tag_for("input", B)
};
EJS.Helpers.prototype.is_current_page = function(A) {
	return (window.location.href == A || window.location.pathname == A ? true
			: false)
};
EJS.Helpers.prototype.link_to = function(B, A, C) {
	if (!B) {
		var B = "null"
	}
	if (!C) {
		var C = {}
	}
	if (C.confirm) {
		C.onclick = ' var ret_confirm = confirm("' + C.confirm
				+ '"); if(!ret_confirm){ return false;} ';
		C.confirm = null
	}
	C.href = A;
	return this.start_tag_for("a", C) + B + this.tag_end("a")
};
EJS.Helpers.prototype.submit_link_to = function(B, A, C) {
	if (!B) {
		var B = "null"
	}
	if (!C) {
		var C = {}
	}
	C.onclick = C.onclick || "";
	if (C.confirm) {
		C.onclick = ' var ret_confirm = confirm("' + C.confirm
				+ '"); if(!ret_confirm){ return false;} ';
		C.confirm = null
	}
	C.value = B;
	C.type = "submit";
	C.onclick = C.onclick + (A ? this.url_for(A) : "") + "return false;";
	return this.start_tag_for("input", C)
};
EJS.Helpers.prototype.link_to_if = function(F, B, A, D, C, E) {
	return this.link_to_unless((F == false), B, A, D, C, E)
};
EJS.Helpers.prototype.link_to_unless = function(E, B, A, C, D) {
	C = C || {};
	if (E) {
		if (D && typeof D == "function") {
			return D(B, A, C, D)
		} else {
			return B
		}
	} else {
		return this.link_to(B, A, C)
	}
};
EJS.Helpers.prototype.link_to_unless_current = function(B, A, C, D) {
	C = C || {};
	return this.link_to_unless(this.is_current_page(A), B, A, C, D)
};
EJS.Helpers.prototype.password_field_tag = function(A, C, B) {
	return this.input_field_tag(A, C, "password", B)
};
EJS.Helpers.prototype.select_tag = function(D, G, H, F) {
	F = F || {};
	F.id = F.id || D;
	F.value = G;
	F.name = D;
	var B = "";
	B += this.start_tag_for("select", F);
	for ( var E = 0; E < H.length; E++) {
		var C = H[E];
		var A = {
			value : C.value
		};
		if (C.value == G) {
			A.selected = "selected"
		}
		B += this.start_tag_for("option", A) + C.text + this.tag_end("option")
	}
	B += this.tag_end("select");
	return B
};
EJS.Helpers.prototype.single_tag_for = function(A, B) {
	return this.tag(A, B, "/>")
};
EJS.Helpers.prototype.start_tag_for = function(A, B) {
	return this.tag(A, B)
};
EJS.Helpers.prototype.submit_tag = function(A, B) {
	B = B || {};
	B.type = B.type || "submit";
	B.value = A || "Submit";
	return this.single_tag_for("input", B)
};
EJS.Helpers.prototype.tag = function(C, E, D) {
	if (!D) {
		var D = ">"
	}
	var B = " ";
	for ( var A in E) {
		if (E[A] != null) {
			var F = E[A].toString()
		} else {
			var F = ""
		}
		if (A == "Class") {
			A = "class"
		}
		if (F.indexOf("'") != -1) {
			B += A + '="' + F + '" '
		} else {
			B += A + "='" + F + "' "
		}
	}
	return "<" + C + B + D
};
EJS.Helpers.prototype.tag_end = function(A) {
	return "</" + A + ">"
};
EJS.Helpers.prototype.text_area_tag = function(A, C, B) {
	B = B || {};
	B.id = B.id || A;
	B.name = B.name || A;
	C = C || "";
	if (B.size) {
		B.cols = B.size.split("x")[0];
		B.rows = B.size.split("x")[1];
		delete B.size
	}
	B.cols = B.cols || 50;
	B.rows = B.rows || 4;
	return this.start_tag_for("textarea", B) + C + this.tag_end("textarea")
};
EJS.Helpers.prototype.text_tag = EJS.Helpers.prototype.text_area_tag;
EJS.Helpers.prototype.text_field_tag = function(A, C, B) {
	return this.input_field_tag(A, C, "text", B)
};
EJS.Helpers.prototype.url_for = function(A) {
	return 'window.location="' + A + '";'
};
EJS.Helpers.prototype.img_tag = function(B, C, A) {
	A = A || {};
	A.src = B;
	A.alt = C;
	return this.single_tag_for("img", A)
}